R is an open source programming language that is popular for
statistics and data analysis. R was built by statisticians, so many
common statistical operations are built into the base language. R also
features powerful and intuitive libraries for plotting and a variety of
packages for predictive modeling, making it one of the most popular
languages for data science.
Data Types
Decimal numbers (real numbers) in R are known as doubles. Doubles are
the default numeric data type so when you manually enter a number in R,
you are working with a double.
typeof(1)
[1] "double"
typeof(-10.5)
[1] "double"
typeof(Inf)
[1] "double"
typeof(-Inf)
[1] "double"
typeof(NaN) # dividing zero by zero produces NaN
[1] "double"
Integers are a second numeric data type that only take whole numbered
values.
as.integer(1) # Convert the double 1 to integer 1
[1] 1
typeof(as.integer(1))
[1] "integer"
# Convert back from integer to double
as.numeric(as.integer(1))
[1] 1
Our first non-numeric data type is the Logical. A Logical takes on
the value of TRUE or FALSE. You must type TRUE and FALSE in all capital
letters for R to recognize them as logical values. Data that only takes
on the values of True or False are also called “Booleans”.
typeof(TRUE)
[1] "logical"
typeof(FALSE)
[1] "logical"
typeof(T)
[1] "logical"
typeof(F)
[1] "logical"
You can create logical values with logical comparisons. R supports a
variety of standard logic comparison operators including > (greater
than), < (less than), >= (greater than or equal), <= (less than
or equal).
20 > 20
[1] FALSE
20 >= 20
[1] TRUE
10 == 10
[1] TRUE
10 != 20
[1] TRUE
!FALSE
[1] TRUE
(2 > 1) & (10 == 9)
[1] FALSE
(2 > 1) | (10 == 9)
[1] TRUE
Strings of text in R are known as characters. Surround text with
quotation marks to create a character.
typeof("cat")
[1] "character"
typeof("1")
[1] "character"
typeof(as.numeric("12"))
[1] "double"
typeof(as.character(12))
[1] "character"
Simple Arithmetic Operations¶
12 + 6 # addition
[1] 18
12 - 6 # subtraction
[1] 6
12 * 6 # multiplication
[1] 72
12 / 6 # division
[1] 2
12^6 # exponentiation
[1] 2985984
12**6 # exponentiation
[1] 2985984
12 %% 6 # modulo (get remainder)
[1] 0
Variables
A variable is a name you assign a value or object. After assigning a
variable, you can access its associated value or object using the
variable’s name. To simply put, this is how we store data. In R, assign
variables using <- (the less than sign followed by a hyphen.).
var <- 3 + 3
x <- 10
y <- "R Workshop"
z <- (sqrt(144) == 12)
print(var)
[1] 6
print(x)
[1] 10
print(y)
[1] "R Workshop"
print(z)
[1] TRUE
It is possible to assign variables in R using the equals symbol =
instead of <-. The equal sign is used for variable assignment in many
other programming languages (such as Python). One reason for using <-
besides conforming to the style preferred by the R community is that the
equals sign is used in places other than variable assignment statements.
Functions often take named arguments and when calling a function you use
the = symbol to assign values to named arguments.
Vectors or Collections
A vector is a sequence of data elements of the same data type. You
can have numeric, logical and character vectors.
To create and store a vector with specific values, use the c()
function and assign the result to a variable. c() takes a comma
separated sequence of elements as input and combines them into a vector.
You can also combine two vectors using the c() function. If you try to
combine vectors of different types, R will automatically convert the
vectors into the type that fits best.
# Creating a character vector for the days of the week
weekday <- c("Monday", "Tuesday", "Wednesday", "Thursday", "Friday")
weekend <- c("Saturday", "Sunday")
days <- c(weekday, weekend)
print(days)
[1] "Monday" "Tuesday" "Wednesday" "Thursday" "Friday" "Saturday" "Sunday"
Vector Indexing Starts at 1
The first element is at index position 1, the second element is at
index position 2 and so on.
*Note: unlike many other programming languages, indexes in R start at
1 instead of 0.
When you print a vector to the screen, each line starts with a number
in square brackets followed by vector values. The number in square
brackets indicates the index of the next value listed on that line.
You can access a specific value in a vector by typing the name of the
vector and then wrapping the index associated with the value you want to
access in square brackets.
days[1]
[1] "Monday"
Range of Values: Inclusive
You can access ranges of values by placing a colon between the
starting and ending indices of the range:
days[1:3]
[1] "Monday" "Tuesday" "Wednesday"
Pulling out specific elements from Vectors
days[c(1, 3, 5, 7)]
[1] "Monday" "Wednesday" "Friday" "Sunday"
Subset out of a Collection
A subset of a vector is just a shorter vector. You can access a
specific subset of values by wrapping a vector in the square
brackets.
weekdays <- days[1:5]
weekdays
[1] "Monday" "Tuesday" "Wednesday" "Thursday" "Friday"
Generate a vector using 100 random Numbers
random_data <- runif(100) # Create a vector of 100 random numbers
print(random_data)
[1] 0.601253516 0.719215520 0.428791696 0.954586146 0.002825221 0.912358903 0.094981659 0.465619302 0.210666870 0.902174364 0.396719641 0.322112673 0.511106455
[14] 0.521341122 0.363127518 0.366527548 0.527183666 0.685147211 0.519944513 0.591298793 0.061995111 0.302844349 0.880424201 0.365061312 0.463684499 0.804066397
[27] 0.148957152 0.287857758 0.093952734 0.758151887 0.103074430 0.892897486 0.579773317 0.798398663 0.603510989 0.241194112 0.231561340 0.785641948 0.750667124
[40] 0.190808424 0.629992959 0.855862409 0.412287503 0.960019909 0.404498031 0.570024413 0.959659815 0.174513218 0.053899949 0.672869894 0.142749767 0.654829003
[53] 0.636226679 0.926860283 0.955050981 0.599153793 0.263378433 0.476719820 0.997212063 0.814981470 0.173799206 0.036244909 0.628301271 0.296626335 0.121297164
[66] 0.512687834 0.130345278 0.447331684 0.881440107 0.949472001 0.755979348 0.818791750 0.915813698 0.853843003 0.740594027 0.806554129 0.891963726 0.786478848
[79] 0.098086106 0.034598737 0.606487290 0.959551943 0.111269935 0.825509603 0.398758434 0.633334293 0.279467671 0.517837560 0.080050943 0.527193833 0.357329777
[92] 0.862411802 0.275236687 0.071194843 0.681278336 0.465154053 0.468364371 0.391514763 0.098308521 0.022964923
print(length(random_data))
[1] 100
Filtering of Vectors using Logical Expressions You
can also index a vector with a logical vector of the same length. In
this case, the subset is created from each index where the corresponding
logical vector is TRUE. Indexing with a logical vector is a common way
to filter a numeric or character vector for values that fulfill certain
criteria.
# Exclude everything except for your specified index
y <- c(1, 0, 3)
y <- y[-2]
y
[1] 1 3
# Exclude the range 2 to 9
random_data <- runif(50)
random_data_sub <- random_data[-(2:49)]
random_data_sub
[1] 0.2665789 0.3968453
# Exclude using logical expression
over_half <- (random_data > 0.5)
new_subset <- random_data[over_half]
new_subset
[1] 0.9513518 0.9196884 0.6220517 0.6799197 0.8695307 0.7120434 0.8860579 0.5192011 0.6553047 0.8639851 0.6851627 0.7975867 0.8037875 0.5572514 0.9958366 0.5052394
[17] 0.5590207 0.9668272 0.6954043 0.7933677 0.6393207 0.9396667 0.8633686 0.7923260 0.7717887 0.9555974 0.9679353 0.8015830 0.5403477 0.7434739
Use %in% to filter a vector
my_letters <- c("a", "b", "c", "d", "a", "c")
# Get only the a's and c's
my_letters[my_letters %in% c("a", "c")]
[1] "a" "c" "a" "c"
Vectorized Operations
Many R functions and operations behave in a “vectorized” manner,
meaning they act upon each element of a vector individually and return
the result of each of the operations in a new vector. Vectorized
operations simplify the process of performing the same calculations on
related data. All the basic operators and functions we’ve learned so far
that operate on single values work on vectors longer than length 1.
example_vector <- c(1, 2, 3)
# adds to each value in the vector
example_vector + 10
[1] 11 12 13
# performs subtraction on each value
example_vector - 10
[1] -9 -8 -7
Different Ways to Generate Vectors
x <- 1:20
y <- seq(from = 1, to = 20, by = 2)
r <- rep(1, times = 10)
s <- runif(n = 5, min = 0, max = 100)
x
[1] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
y
[1] 1 3 5 7 9 11 13 15 17 19
r
[1] 1 1 1 1 1 1 1 1 1 1
s
[1] 74.66618 93.12643 14.42880 74.82574 60.27581
Control Flow
If, Else and Else If
An if statement checks whether some logical expression is true or
false and executes a specified block of code if the logical expression
is true.
In R, an if statement starts with if, followed by a logical
expression in parentheses, followed by the code to execute when the if
statement is true in curly braces.
If statements are often accompanied by else statements. Else
statements come after if statements and allow you to execute code in the
event that the logical expression of an if statement is false.
x <- 5
if (x > 0) {
print("Positive number")
} else {
print("Negative number")
}
[1] "Positive number"
For Loops
For loops are a programming construct that let you go through each
item in a sequence and then perform some operation on each one.
my_sequence <- seq(0, 100, 10)
# Create a new loop over the specified items
for (item in my_sequence) {
print(item)
}
[1] 0
[1] 10
[1] 20
[1] 30
[1] 40
[1] 50
[1] 60
[1] 70
[1] 80
[1] 90
[1] 100
The next keyword causes a for loop to skip to the next
iteration of the loop.
my_sequence <- seq(0, 100, 10)
for (item in my_sequence) {
if (item < 50) { # this if statement skips items less than 50
next
}
print(item)
}
[1] 50
[1] 60
[1] 70
[1] 80
[1] 90
[1] 100
The break keyword halts the execution of the loop entirely.
Use break to break out of a loop.
my_sequence <- seq(0, 100, 10)
for (item in my_sequence) {
if (item > 50) {
break
}
print(item)
}
[1] 0
[1] 10
[1] 20
[1] 30
[1] 40
[1] 50
While Loops
While loops are similar to for loops in that they allow you to
execute code over and over again. For loops execute their contents, at
most, a number of iterations equal to the length of the sequence you are
looping over. While loops, on the other hand, keep executing
their contents as long as a certain logical expression you supply
remains true.
x <- 5
iterations <- 0
# Execute as long as iterations < x
while (iterations < x) {
print("Study")
iterations <- iterations + 1 # Increment iterations by 1 each time the loop executes
}
[1] "Study"
[1] "Study"
[1] "Study"
[1] "Study"
[1] "Study"
If Else on Vectors
For example, imagine you have a vector of numbers and you want to set
all the negative values in the vector to zero. One way to do it is to
use a for loop with an inner if statement.
my_vect <- runif(25, -1, 1) # Generate some random data between -1 and 1
for (index in 1:length(my_vect)) { # loop through the sequence 1:25
number <- my_vect[index] # look up the next number using indexing
if (number < 0) { # check if the number is less than 0
my_vect[index] <- 0 # if so, set it to 0
}
}
print(my_vect)
[1] 0.0000000 0.0000000 0.9865759 0.3029479 0.5311695 0.0000000 0.8078285 0.0000000 0.6218120 0.0000000 0.0000000 0.0000000 0.3058018 0.0000000 0.0000000 0.5942243
[17] 0.0000000 0.0000000 0.0000000 0.0000000 0.6908745 0.4105624 0.6997950 0.0000000 0.8020392
Using a for loop requires writing quite a bit of code and loops are
not particularly fast.
Instead we could have used R’s ifelse() function to the same thing in
a vectorized manner. ifelse() takes a logical test as the first
argument, a value to return if the test is true as the second argument
and a value to return if the test is false as the third argument:
data <- c(11, 7, NA, 9, NA, 13, 15, NaN, 19, 17, 14, NaN)
# Use if else statements to conditionally fill these bad values with the mean
ifelse(is.na(data) | is.nan(data), # logical check
mean(data, na.rm = T), # value to set if TRUE
data
) # value to set if FALSE
[1] 11.000 7.000 13.125 9.000 13.125 13.000 15.000 13.125 19.000 17.000 14.000 13.125
# Chaining ifelse to perform multiple operations
data <- c(11, 7, NA, 9, NA, 13, 15, NaN, 19, 17, 14, NaN)
d <- ifelse(is.na(data) | is.nan(data), "missing", ifelse(data < 10, "low", ifelse(data < 15, "medium", "high")))
table(d)
d
high low medium missing
3 2 3 4
Functions
A function is just an R object that runs a per-defined snippet of
code, usually on some input that you supply to it. A function can return
an output based on the input you provide. For example, the sum()
function built into R simply takes a numeric vector as input and returns
their sum as output. Built-in functions and packages can take you a long
way in R, but it can be useful to define your own functions to perform
specific tasks outside the scope of built-in functions.
Create your own function in R using this syntax:
# Assign the function() to a name and declare arguments within ()
new_function <- function(arguments) {
# Write a function body within the {} to execute
for (x in 1:arguments) {
print("This is a function!")
}
}
Here is an actual example
exampleFunction <- function(x, y) {
c(x + 1, y + 10)
}
exampleFunction(2, 4)
[1] 3 14
Functions with Return Value
Functions in R return the last expression evaluated by default.
add_10 <- function(number) {
number + 10
# return (number+10)
}
add_10(5)
[1] 15
add_20 <- function(number) {
return(number + 20) # Exit and return specified value
number + 10 # The function exits before running this line
}
Function Arguments
A function can have one or more named arguments. You can assign a
default value to an argument when creating a function with the
argument_name = argument_value syntax.
sum_3_items <- function(x, y, z, print_args = TRUE) {
if (print_args) {
print(x)
print(y)
print(z)
}
return(x + y + z)
}
sum <- sum_3_items(1, 2, 3)
[1] 1
[1] 2
[1] 3
sum2 <- sum_3_items(10, 20, 30, print_args = FALSE)
Ellipsis
The … argument collects all extra arguments passed to a function that
are not matched. The … argument can be used in functions where the
number of arguments is not known in advance.
addition_function <- function(...) {
total <- 0
# list (...) extracts the arguments to a list
for (value in list(...)) {
# Add each argument in ... to the total
total <- total + value
}
total
}
addition_function(2, 4, 6, 8, 10, 12, 14)
[1] 56
LS0tDQp0aXRsZTogIkludHJvZHVjdGlvbiB0byBSIFN5bnRheCINCmF1dGhvcjogRGFwaG5lIEphbmVseW4gTC4gR29eW0RlIExhIFNhbGxlIFVuaXZlcnNpdHksIE1hbmlsYSwgUGhpbGlwcGluZXMsIGRhcGhuZV9qYW5lbHluX2dvQGRsc3UuZWR1LnBoXQ0Kb3V0cHV0OiBodG1sX25vdGVib29rDQotLS0NCg0KUiBpcyBhbiBvcGVuIHNvdXJjZSBwcm9ncmFtbWluZyBsYW5ndWFnZSB0aGF0IGlzIHBvcHVsYXIgZm9yIHN0YXRpc3RpY3MgYW5kIGRhdGEgYW5hbHlzaXMuIFIgd2FzIGJ1aWx0IGJ5IHN0YXRpc3RpY2lhbnMsIHNvIG1hbnkgY29tbW9uIHN0YXRpc3RpY2FsIG9wZXJhdGlvbnMgYXJlIGJ1aWx0IGludG8gdGhlIGJhc2UgbGFuZ3VhZ2UuIFIgYWxzbyBmZWF0dXJlcyBwb3dlcmZ1bCBhbmQgaW50dWl0aXZlIGxpYnJhcmllcyBmb3IgcGxvdHRpbmcgYW5kIGEgdmFyaWV0eSBvZiBwYWNrYWdlcyBmb3IgcHJlZGljdGl2ZSBtb2RlbGluZywgbWFraW5nIGl0IG9uZSBvZiB0aGUgbW9zdCBwb3B1bGFyIGxhbmd1YWdlcyBmb3IgZGF0YSBzY2llbmNlLg0KDQojIyBEYXRhIFR5cGVzDQoNCkRlY2ltYWwgbnVtYmVycyAocmVhbCBudW1iZXJzKSBpbiBSIGFyZSBrbm93biBhcyBkb3VibGVzLiBEb3VibGVzIGFyZSB0aGUgZGVmYXVsdCBudW1lcmljIGRhdGEgdHlwZSBzbyB3aGVuIHlvdSBtYW51YWxseSBlbnRlciBhIG51bWJlciBpbiBSLCB5b3UgYXJlIHdvcmtpbmcgd2l0aCBhIGRvdWJsZS4NCg0KYGBge3J9DQp0eXBlb2YoMSkNCnR5cGVvZigtMTAuNSkNCnR5cGVvZihJbmYpDQp0eXBlb2YoLUluZikNCnR5cGVvZihOYU4pICMgZGl2aWRpbmcgemVybyBieSB6ZXJvIHByb2R1Y2VzIE5hTg0KYGBgDQoNCkludGVnZXJzIGFyZSBhIHNlY29uZCBudW1lcmljIGRhdGEgdHlwZSB0aGF0IG9ubHkgdGFrZSB3aG9sZSBudW1iZXJlZCB2YWx1ZXMuDQoNCmBgYHtyfQ0KYXMuaW50ZWdlcigxKSAjIENvbnZlcnQgdGhlIGRvdWJsZSAxIHRvIGludGVnZXIgMQ0KdHlwZW9mKGFzLmludGVnZXIoMSkpDQoNCiMgQ29udmVydCBiYWNrIGZyb20gaW50ZWdlciB0byBkb3VibGUNCmFzLm51bWVyaWMoYXMuaW50ZWdlcigxKSkNCmBgYA0KDQpPdXIgZmlyc3Qgbm9uLW51bWVyaWMgZGF0YSB0eXBlIGlzIHRoZSBMb2dpY2FsLiBBIExvZ2ljYWwgdGFrZXMgb24gdGhlIHZhbHVlIG9mIFRSVUUgb3IgRkFMU0UuIFlvdSBtdXN0IHR5cGUgVFJVRSBhbmQgRkFMU0UgaW4gYWxsIGNhcGl0YWwgbGV0dGVycyBmb3IgUiB0byByZWNvZ25pemUgdGhlbSBhcyBsb2dpY2FsIHZhbHVlcy4gRGF0YSB0aGF0IG9ubHkgdGFrZXMgb24gdGhlIHZhbHVlcyBvZiBUcnVlIG9yIEZhbHNlIGFyZSBhbHNvIGNhbGxlZCAiQm9vbGVhbnMiLg0KDQpgYGB7cn0NCnR5cGVvZihUUlVFKQ0KdHlwZW9mKEZBTFNFKQ0KdHlwZW9mKFQpDQp0eXBlb2YoRikNCmBgYA0KDQpZb3UgY2FuIGNyZWF0ZSBsb2dpY2FsIHZhbHVlcyB3aXRoIGxvZ2ljYWwgY29tcGFyaXNvbnMuIFIgc3VwcG9ydHMgYSB2YXJpZXR5IG9mIHN0YW5kYXJkIGxvZ2ljIGNvbXBhcmlzb24gb3BlcmF0b3JzIGluY2x1ZGluZyA+IChncmVhdGVyIHRoYW4pLCA8IChsZXNzIHRoYW4pLCA+PSAoZ3JlYXRlciB0aGFuIG9yIGVxdWFsKSwgPD0gKGxlc3MgdGhhbiBvciBlcXVhbCkuDQoNCmBgYHtyfQ0KMjAgPiAyMA0KMjAgPj0gMjANCjEwID09IDEwDQoxMCAhPSAyMA0KIUZBTFNFDQoNCigyID4gMSkgJiAoMTAgPT0gOSkNCigyID4gMSkgfCAoMTAgPT0gOSkNCmBgYA0KDQpTdHJpbmdzIG9mIHRleHQgaW4gUiBhcmUga25vd24gYXMgY2hhcmFjdGVycy4gU3Vycm91bmQgdGV4dCB3aXRoIHF1b3RhdGlvbiBtYXJrcyB0byBjcmVhdGUgYSBjaGFyYWN0ZXIuDQoNCmBgYHtyfQ0KdHlwZW9mKCJjYXQiKQ0KdHlwZW9mKCIxIikNCnR5cGVvZihhcy5udW1lcmljKCIxMiIpKQ0KdHlwZW9mKGFzLmNoYXJhY3RlcigxMikpDQpgYGANCg0KIyMgU2ltcGxlIEFyaXRobWV0aWMgT3BlcmF0aW9uc8K2DQoNCmBgYHtyfQ0KMTIgKyA2ICMgYWRkaXRpb24NCjEyIC0gNiAjIHN1YnRyYWN0aW9uDQoxMiAqIDYgIyBtdWx0aXBsaWNhdGlvbg0KMTIgLyA2ICMgZGl2aXNpb24NCjEyXjYgIyBleHBvbmVudGlhdGlvbg0KMTIqKjYgIyBleHBvbmVudGlhdGlvbg0KMTIgJSUgNiAjIG1vZHVsbyAoZ2V0IHJlbWFpbmRlcikNCmBgYA0KDQojIyBWYXJpYWJsZXMNCg0KQSB2YXJpYWJsZSBpcyBhIG5hbWUgeW91IGFzc2lnbiBhIHZhbHVlIG9yIG9iamVjdC4gQWZ0ZXIgYXNzaWduaW5nIGEgdmFyaWFibGUsIHlvdSBjYW4gYWNjZXNzIGl0cyBhc3NvY2lhdGVkIHZhbHVlIG9yIG9iamVjdCB1c2luZyB0aGUgdmFyaWFibGUncyBuYW1lLiBUbyBzaW1wbHkgcHV0LCB0aGlzIGlzIGhvdyB3ZSBzdG9yZSBkYXRhLiBJbiBSLCBhc3NpZ24gdmFyaWFibGVzIHVzaW5nIDwtICh0aGUgbGVzcyB0aGFuIHNpZ24gZm9sbG93ZWQgYnkgYSBoeXBoZW4uKS4NCg0KYGBge3J9DQp2YXIgPC0gMyArIDMNCnggPC0gMTANCnkgPC0gIlIgV29ya3Nob3AiDQp6IDwtIChzcXJ0KDE0NCkgPT0gMTIpDQoNCnByaW50KHZhcikNCnByaW50KHgpDQpwcmludCh5KQ0KcHJpbnQoeikNCmBgYA0KDQpJdCBpcyBwb3NzaWJsZSB0byBhc3NpZ24gdmFyaWFibGVzIGluIFIgdXNpbmcgdGhlIGVxdWFscyBzeW1ib2wgPSBpbnN0ZWFkIG9mIDwtLiBUaGUgZXF1YWwgc2lnbiBpcyB1c2VkIGZvciB2YXJpYWJsZSBhc3NpZ25tZW50IGluIG1hbnkgb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzIChzdWNoIGFzIFB5dGhvbikuIE9uZSByZWFzb24gZm9yIHVzaW5nIDwtIGJlc2lkZXMgY29uZm9ybWluZyB0byB0aGUgc3R5bGUgcHJlZmVycmVkIGJ5IHRoZSBSIGNvbW11bml0eSBpcyB0aGF0IHRoZSBlcXVhbHMgc2lnbiBpcyB1c2VkIGluIHBsYWNlcyBvdGhlciB0aGFuIHZhcmlhYmxlIGFzc2lnbm1lbnQgc3RhdGVtZW50cy4gRnVuY3Rpb25zIG9mdGVuIHRha2UgbmFtZWQgYXJndW1lbnRzIGFuZCB3aGVuIGNhbGxpbmcgYSBmdW5jdGlvbiB5b3UgdXNlIHRoZSA9IHN5bWJvbCB0byBhc3NpZ24gdmFsdWVzIHRvIG5hbWVkIGFyZ3VtZW50cy4NCg0KIyMgVmVjdG9ycyBvciBDb2xsZWN0aW9ucw0KDQpBIHZlY3RvciBpcyBhIHNlcXVlbmNlIG9mIGRhdGEgZWxlbWVudHMgb2YgdGhlIHNhbWUgZGF0YSB0eXBlLiBZb3UgY2FuIGhhdmUgbnVtZXJpYywgbG9naWNhbCBhbmQgY2hhcmFjdGVyIHZlY3RvcnMuDQoNClRvIGNyZWF0ZSBhbmQgc3RvcmUgYSB2ZWN0b3Igd2l0aCBzcGVjaWZpYyB2YWx1ZXMsIHVzZSB0aGUgYygpIGZ1bmN0aW9uIGFuZCBhc3NpZ24gdGhlIHJlc3VsdCB0byBhIHZhcmlhYmxlLiBjKCkgdGFrZXMgYSBjb21tYSBzZXBhcmF0ZWQgc2VxdWVuY2Ugb2YgZWxlbWVudHMgYXMgaW5wdXQgYW5kIGNvbWJpbmVzIHRoZW0gaW50byBhIHZlY3Rvci4gWW91IGNhbiBhbHNvIGNvbWJpbmUgdHdvIHZlY3RvcnMgdXNpbmcgdGhlIGMoKSBmdW5jdGlvbi4gSWYgeW91IHRyeSB0byBjb21iaW5lIHZlY3RvcnMgb2YgZGlmZmVyZW50IHR5cGVzLCBSIHdpbGwgYXV0b21hdGljYWxseSBjb252ZXJ0IHRoZSB2ZWN0b3JzIGludG8gdGhlIHR5cGUgdGhhdCBmaXRzIGJlc3QuDQoNCmBgYHtyfQ0KIyBDcmVhdGluZyBhIGNoYXJhY3RlciB2ZWN0b3IgZm9yIHRoZSBkYXlzIG9mIHRoZSB3ZWVrDQp3ZWVrZGF5IDwtIGMoIk1vbmRheSIsICJUdWVzZGF5IiwgIldlZG5lc2RheSIsICJUaHVyc2RheSIsICJGcmlkYXkiKQ0KDQp3ZWVrZW5kIDwtIGMoIlNhdHVyZGF5IiwgIlN1bmRheSIpDQoNCmRheXMgPC0gYyh3ZWVrZGF5LCB3ZWVrZW5kKQ0KDQpwcmludChkYXlzKQ0KYGBgDQoNCioqVmVjdG9yIEluZGV4aW5nIFN0YXJ0cyBhdCAxKioNCg0KVGhlIGZpcnN0IGVsZW1lbnQgaXMgYXQgaW5kZXggcG9zaXRpb24gMSwgdGhlIHNlY29uZCBlbGVtZW50IGlzIGF0IGluZGV4IHBvc2l0aW9uIDIgYW5kIHNvIG9uLg0KDQoqTm90ZTogdW5saWtlIG1hbnkgb3RoZXIgcHJvZ3JhbW1pbmcgbGFuZ3VhZ2VzLCBpbmRleGVzIGluIFIgc3RhcnQgYXQgMSBpbnN0ZWFkIG9mIDAuDQoNCldoZW4geW91IHByaW50IGEgdmVjdG9yIHRvIHRoZSBzY3JlZW4sIGVhY2ggbGluZSBzdGFydHMgd2l0aCBhIG51bWJlciBpbiBzcXVhcmUgYnJhY2tldHMgZm9sbG93ZWQgYnkgdmVjdG9yIHZhbHVlcy4gVGhlIG51bWJlciBpbiBzcXVhcmUgYnJhY2tldHMgaW5kaWNhdGVzIHRoZSBpbmRleCBvZiB0aGUgbmV4dCB2YWx1ZSBsaXN0ZWQgb24gdGhhdCBsaW5lLg0KDQpZb3UgY2FuIGFjY2VzcyBhIHNwZWNpZmljIHZhbHVlIGluIGEgdmVjdG9yIGJ5IHR5cGluZyB0aGUgbmFtZSBvZiB0aGUgdmVjdG9yIGFuZCB0aGVuIHdyYXBwaW5nIHRoZSBpbmRleCBhc3NvY2lhdGVkIHdpdGggdGhlIHZhbHVlIHlvdSB3YW50IHRvIGFjY2VzcyBpbiBzcXVhcmUgYnJhY2tldHMuDQoNCmBgYHtyfQ0KZGF5c1sxXQ0KYGBgDQoNCioqUmFuZ2Ugb2YgVmFsdWVzOiBJbmNsdXNpdmUqKg0KDQpZb3UgY2FuIGFjY2VzcyByYW5nZXMgb2YgdmFsdWVzIGJ5IHBsYWNpbmcgYSBjb2xvbiBiZXR3ZWVuIHRoZSBzdGFydGluZyBhbmQgZW5kaW5nIGluZGljZXMgb2YgdGhlIHJhbmdlOg0KDQpgYGB7cn0NCmRheXNbMTozXQ0KYGBgDQoNCioqUHVsbGluZyBvdXQgc3BlY2lmaWMgZWxlbWVudHMgZnJvbSBWZWN0b3JzKioNCg0KYGBge3J9DQpkYXlzW2MoMSwgMywgNSwgNyldDQpgYGANCg0KKipTdWJzZXQgb3V0IG9mIGEgQ29sbGVjdGlvbioqDQoNCkEgc3Vic2V0IG9mIGEgdmVjdG9yIGlzIGp1c3QgYSBzaG9ydGVyIHZlY3Rvci4gWW91IGNhbiBhY2Nlc3MgYSBzcGVjaWZpYyBzdWJzZXQgb2YgdmFsdWVzIGJ5IHdyYXBwaW5nIGEgdmVjdG9yIGluIHRoZSBzcXVhcmUgYnJhY2tldHMuDQoNCmBgYHtyfQ0Kd2Vla2RheXMgPC0gZGF5c1sxOjVdDQp3ZWVrZGF5cw0KYGBgDQoNCioqR2VuZXJhdGUgYSB2ZWN0b3IgdXNpbmcgMTAwIHJhbmRvbSBOdW1iZXJzKioNCg0KYGBge3J9DQpyYW5kb21fZGF0YSA8LSBydW5pZigxMDApICMgQ3JlYXRlIGEgdmVjdG9yIG9mIDEwMCByYW5kb20gbnVtYmVycw0KDQpwcmludChyYW5kb21fZGF0YSkNCnByaW50KGxlbmd0aChyYW5kb21fZGF0YSkpDQpgYGANCg0KKipGaWx0ZXJpbmcgb2YgVmVjdG9ycyB1c2luZyBMb2dpY2FsIEV4cHJlc3Npb25zKioNCllvdSBjYW4gYWxzbyBpbmRleCBhIHZlY3RvciB3aXRoIGEgbG9naWNhbCB2ZWN0b3Igb2YgdGhlIHNhbWUgbGVuZ3RoLiBJbiB0aGlzIGNhc2UsIHRoZSBzdWJzZXQgaXMgY3JlYXRlZCBmcm9tIGVhY2ggaW5kZXggd2hlcmUgdGhlIGNvcnJlc3BvbmRpbmcgbG9naWNhbCB2ZWN0b3IgaXMgVFJVRS4gSW5kZXhpbmcgd2l0aCBhIGxvZ2ljYWwgdmVjdG9yIGlzIGEgY29tbW9uIHdheSB0byBmaWx0ZXIgYSBudW1lcmljIG9yIGNoYXJhY3RlciB2ZWN0b3IgZm9yIHZhbHVlcyB0aGF0IGZ1bGZpbGwgY2VydGFpbiBjcml0ZXJpYS4NCg0KYGBge3J9DQojIEV4Y2x1ZGUgZXZlcnl0aGluZyBleGNlcHQgZm9yIHlvdXIgc3BlY2lmaWVkIGluZGV4DQoNCnkgPC0gYygxLCAwLCAzKQ0KeSA8LSB5Wy0yXQ0KeQ0KDQojIEV4Y2x1ZGUgdGhlIHJhbmdlIDIgdG8gOQ0KcmFuZG9tX2RhdGEgPC0gcnVuaWYoNTApDQpyYW5kb21fZGF0YV9zdWIgPC0gcmFuZG9tX2RhdGFbLSgyOjQ5KV0NCnJhbmRvbV9kYXRhX3N1Yg0KDQojIEV4Y2x1ZGUgdXNpbmcgbG9naWNhbCBleHByZXNzaW9uDQpvdmVyX2hhbGYgPC0gKHJhbmRvbV9kYXRhID4gMC41KQ0KbmV3X3N1YnNldCA8LSByYW5kb21fZGF0YVtvdmVyX2hhbGZdDQpuZXdfc3Vic2V0DQpgYGANCg0KKipVc2UgJWluJSB0byBmaWx0ZXIgYSB2ZWN0b3IqKg0KYGBge3J9DQpteV9sZXR0ZXJzIDwtIGMoImEiLCAiYiIsICJjIiwgImQiLCAiYSIsICJjIikNCg0KIyBHZXQgb25seSB0aGUgYSdzIGFuZCBjJ3MNCm15X2xldHRlcnNbbXlfbGV0dGVycyAlaW4lIGMoImEiLCAiYyIpXQ0KYGBgDQoNCiMjIFZlY3Rvcml6ZWQgT3BlcmF0aW9ucw0KDQpNYW55IFIgZnVuY3Rpb25zIGFuZCBvcGVyYXRpb25zIGJlaGF2ZSBpbiBhICJ2ZWN0b3JpemVkIiBtYW5uZXIsIG1lYW5pbmcgdGhleSBhY3QgdXBvbiBlYWNoIGVsZW1lbnQgb2YgYSB2ZWN0b3IgaW5kaXZpZHVhbGx5IGFuZCByZXR1cm4gdGhlIHJlc3VsdCBvZiBlYWNoIG9mIHRoZSBvcGVyYXRpb25zIGluIGEgbmV3IHZlY3Rvci4gVmVjdG9yaXplZCBvcGVyYXRpb25zIHNpbXBsaWZ5IHRoZSBwcm9jZXNzIG9mIHBlcmZvcm1pbmcgdGhlIHNhbWUgY2FsY3VsYXRpb25zIG9uIHJlbGF0ZWQgZGF0YS4gQWxsIHRoZSBiYXNpYyBvcGVyYXRvcnMgYW5kIGZ1bmN0aW9ucyB3ZSd2ZSBsZWFybmVkIHNvIGZhciB0aGF0IG9wZXJhdGUgb24gc2luZ2xlIHZhbHVlcyB3b3JrIG9uIHZlY3RvcnMgbG9uZ2VyIHRoYW4gbGVuZ3RoIDEuDQoNCmBgYHtyfQ0KZXhhbXBsZV92ZWN0b3IgPC0gYygxLCAyLCAzKQ0KDQojIGFkZHMgdG8gZWFjaCB2YWx1ZSBpbiB0aGUgdmVjdG9yDQpleGFtcGxlX3ZlY3RvciArIDEwDQoNCiMgcGVyZm9ybXMgc3VidHJhY3Rpb24gb24gZWFjaCB2YWx1ZQ0KZXhhbXBsZV92ZWN0b3IgLSAxMA0KYGBgDQoNCioqRGlmZmVyZW50IFdheXMgdG8gR2VuZXJhdGUgVmVjdG9ycyoqDQpgYGB7cn0NCnggPC0gMToyMA0KeSA8LSBzZXEoZnJvbSA9IDEsIHRvID0gMjAsIGJ5ID0gMikNCnIgPC0gcmVwKDEsIHRpbWVzID0gMTApDQpzIDwtIHJ1bmlmKG4gPSA1LCBtaW4gPSAwLCBtYXggPSAxMDApDQoNCngNCnkNCnINCnMNCmBgYA0KDQojIyBDb250cm9sIEZsb3cNCg0KIyMjIElmLCBFbHNlIGFuZCBFbHNlIElmDQoNCkFuIGlmIHN0YXRlbWVudCBjaGVja3Mgd2hldGhlciBzb21lIGxvZ2ljYWwgZXhwcmVzc2lvbiBpcyB0cnVlIG9yIGZhbHNlIGFuZCBleGVjdXRlcyBhIHNwZWNpZmllZCBibG9jayBvZiBjb2RlIGlmIHRoZSBsb2dpY2FsIGV4cHJlc3Npb24gaXMgdHJ1ZS4NCg0KSW4gUiwgYW4gaWYgc3RhdGVtZW50IHN0YXJ0cyB3aXRoIGlmLCBmb2xsb3dlZCBieSBhIGxvZ2ljYWwgZXhwcmVzc2lvbiBpbiBwYXJlbnRoZXNlcywgZm9sbG93ZWQgYnkgdGhlIGNvZGUgdG8gZXhlY3V0ZSB3aGVuIHRoZSBpZiBzdGF0ZW1lbnQgaXMgdHJ1ZSBpbiBjdXJseSBicmFjZXMuDQoNCklmIHN0YXRlbWVudHMgYXJlIG9mdGVuIGFjY29tcGFuaWVkIGJ5IGVsc2Ugc3RhdGVtZW50cy4gRWxzZSBzdGF0ZW1lbnRzIGNvbWUgYWZ0ZXIgaWYgc3RhdGVtZW50cyBhbmQgYWxsb3cgeW91IHRvIGV4ZWN1dGUgY29kZSBpbiB0aGUgZXZlbnQgdGhhdCB0aGUgbG9naWNhbCBleHByZXNzaW9uIG9mIGFuIGlmIHN0YXRlbWVudCBpcyBmYWxzZS4NCg0KYGBge3J9DQp4IDwtIDUNCmlmICh4ID4gMCkgew0KICBwcmludCgiUG9zaXRpdmUgbnVtYmVyIikNCn0gZWxzZSB7DQogIHByaW50KCJOZWdhdGl2ZSBudW1iZXIiKQ0KfQ0KYGBgDQoNCiMjIyBGb3IgTG9vcHMNCg0KRm9yIGxvb3BzIGFyZSBhIHByb2dyYW1taW5nIGNvbnN0cnVjdCB0aGF0IGxldCB5b3UgZ28gdGhyb3VnaCBlYWNoIGl0ZW0gaW4gYSBzZXF1ZW5jZSBhbmQgdGhlbiBwZXJmb3JtIHNvbWUgb3BlcmF0aW9uIG9uIGVhY2ggb25lLg0KDQpgYGB7cn0NCm15X3NlcXVlbmNlIDwtIHNlcSgwLCAxMDAsIDEwKQ0KDQojIENyZWF0ZSBhIG5ldyBsb29wIG92ZXIgdGhlIHNwZWNpZmllZCBpdGVtcw0KZm9yIChpdGVtIGluIG15X3NlcXVlbmNlKSB7DQogIHByaW50KGl0ZW0pDQp9DQpgYGANCg0KKipUaGUgbmV4dCBrZXl3b3JkIGNhdXNlcyBhIGZvciBsb29wIHRvIHNraXAgdG8gdGhlIG5leHQgaXRlcmF0aW9uIG9mIHRoZSBsb29wLioqDQoNCmBgYHtyfQ0KbXlfc2VxdWVuY2UgPC0gc2VxKDAsIDEwMCwgMTApDQpmb3IgKGl0ZW0gaW4gbXlfc2VxdWVuY2UpIHsNCiAgaWYgKGl0ZW0gPCA1MCkgeyAjIHRoaXMgaWYgc3RhdGVtZW50IHNraXBzIGl0ZW1zIGxlc3MgdGhhbiA1MA0KICAgIG5leHQNCiAgfQ0KICBwcmludChpdGVtKQ0KfQ0KYGBgDQoNCioqVGhlIGJyZWFrIGtleXdvcmQgaGFsdHMgdGhlIGV4ZWN1dGlvbiBvZiB0aGUgbG9vcCBlbnRpcmVseS4gVXNlIGJyZWFrIHRvIGJyZWFrIG91dCBvZiBhIGxvb3AuKioNCg0KYGBge3J9DQpteV9zZXF1ZW5jZSA8LSBzZXEoMCwgMTAwLCAxMCkNCg0KZm9yIChpdGVtIGluIG15X3NlcXVlbmNlKSB7DQogIGlmIChpdGVtID4gNTApIHsNCiAgICBicmVhaw0KICB9DQogIHByaW50KGl0ZW0pDQp9DQpgYGANCg0KIyMjIFdoaWxlIExvb3BzDQoNCldoaWxlIGxvb3BzIGFyZSBzaW1pbGFyIHRvIGZvciBsb29wcyBpbiB0aGF0IHRoZXkgYWxsb3cgeW91IHRvIGV4ZWN1dGUgY29kZSBvdmVyIGFuZCBvdmVyIGFnYWluLiBGb3IgbG9vcHMgZXhlY3V0ZSB0aGVpciBjb250ZW50cywgYXQgbW9zdCwgYSBudW1iZXIgb2YgaXRlcmF0aW9ucyBlcXVhbCB0byB0aGUgbGVuZ3RoIG9mIHRoZSBzZXF1ZW5jZSB5b3UgYXJlIGxvb3Bpbmcgb3Zlci4gV2hpbGUgbG9vcHMsIG9uIHRoZSBvdGhlciBoYW5kLCAqKmtlZXAgZXhlY3V0aW5nIHRoZWlyIGNvbnRlbnRzIGFzIGxvbmcgYXMgYSBjZXJ0YWluIGxvZ2ljYWwgZXhwcmVzc2lvbiB5b3Ugc3VwcGx5IHJlbWFpbnMgdHJ1ZS4qKg0KDQpgYGB7cn0NCnggPC0gNQ0KaXRlcmF0aW9ucyA8LSAwDQoNCiMgRXhlY3V0ZSBhcyBsb25nIGFzIGl0ZXJhdGlvbnMgPCB4DQp3aGlsZSAoaXRlcmF0aW9ucyA8IHgpIHsNCiAgcHJpbnQoIlN0dWR5IikNCiAgaXRlcmF0aW9ucyA8LSBpdGVyYXRpb25zICsgMSAjIEluY3JlbWVudCBpdGVyYXRpb25zIGJ5IDEgZWFjaCB0aW1lIHRoZSBsb29wIGV4ZWN1dGVzDQp9DQpgYGANCg0KIyMjIElmIEVsc2Ugb24gVmVjdG9ycw0KRm9yIGV4YW1wbGUsIGltYWdpbmUgeW91IGhhdmUgYSB2ZWN0b3Igb2YgbnVtYmVycyBhbmQgeW91IHdhbnQgdG8gc2V0IGFsbCB0aGUgbmVnYXRpdmUgdmFsdWVzIGluIHRoZSB2ZWN0b3IgdG8gemVyby4gT25lIHdheSB0byBkbyBpdCBpcyB0byB1c2UgYSBmb3IgbG9vcCB3aXRoIGFuIGlubmVyIGlmIHN0YXRlbWVudC4NCg0KYGBge3J9DQpteV92ZWN0IDwtIHJ1bmlmKDI1LCAtMSwgMSkgIyBHZW5lcmF0ZSBzb21lIHJhbmRvbSBkYXRhIGJldHdlZW4gLTEgYW5kIDENCg0KZm9yIChpbmRleCBpbiAxOmxlbmd0aChteV92ZWN0KSkgeyAjIGxvb3AgdGhyb3VnaCB0aGUgc2VxdWVuY2UgMToyNQ0KICBudW1iZXIgPC0gbXlfdmVjdFtpbmRleF0gIyBsb29rIHVwIHRoZSBuZXh0IG51bWJlciB1c2luZyBpbmRleGluZw0KICBpZiAobnVtYmVyIDwgMCkgeyAjIGNoZWNrIGlmIHRoZSBudW1iZXIgaXMgbGVzcyB0aGFuIDANCiAgICBteV92ZWN0W2luZGV4XSA8LSAwICMgaWYgc28sIHNldCBpdCB0byAwDQogIH0NCn0NCg0KcHJpbnQobXlfdmVjdCkNCmBgYA0KDQpVc2luZyBhIGZvciBsb29wIHJlcXVpcmVzIHdyaXRpbmcgcXVpdGUgYSBiaXQgb2YgY29kZSBhbmQgbG9vcHMgYXJlIG5vdCBwYXJ0aWN1bGFybHkgZmFzdC4NCg0KSW5zdGVhZCB3ZSBjb3VsZCBoYXZlIHVzZWQgUidzIGlmZWxzZSgpIGZ1bmN0aW9uIHRvIHRoZSBzYW1lIHRoaW5nIGluIGEgdmVjdG9yaXplZCBtYW5uZXIuIGlmZWxzZSgpIHRha2VzIGEgbG9naWNhbCB0ZXN0IGFzIHRoZSBmaXJzdCBhcmd1bWVudCwgYSB2YWx1ZSB0byByZXR1cm4gaWYgdGhlIHRlc3QgaXMgdHJ1ZSBhcyB0aGUgc2Vjb25kIGFyZ3VtZW50IGFuZCBhIHZhbHVlIHRvIHJldHVybiBpZiB0aGUgdGVzdCBpcyBmYWxzZSBhcyB0aGUgdGhpcmQgYXJndW1lbnQ6DQoNCmBgYHtyfQ0KZGF0YSA8LSBjKDExLCA3LCBOQSwgOSwgTkEsIDEzLCAxNSwgTmFOLCAxOSwgMTcsIDE0LCBOYU4pDQoNCiMgVXNlIGlmIGVsc2Ugc3RhdGVtZW50cyB0byBjb25kaXRpb25hbGx5IGZpbGwgdGhlc2UgYmFkIHZhbHVlcyB3aXRoIHRoZSBtZWFuDQoNCmlmZWxzZShpcy5uYShkYXRhKSB8IGlzLm5hbihkYXRhKSwgIyBsb2dpY2FsIGNoZWNrDQogIG1lYW4oZGF0YSwgbmEucm0gPSBUKSwgIyB2YWx1ZSB0byBzZXQgaWYgVFJVRQ0KICBkYXRhDQopICMgdmFsdWUgdG8gc2V0IGlmIEZBTFNFDQpgYGANCg0KYGBge3J9DQojIENoYWluaW5nIGlmZWxzZSB0byBwZXJmb3JtIG11bHRpcGxlIG9wZXJhdGlvbnMNCmRhdGEgPC0gYygxMSwgNywgTkEsIDksIE5BLCAxMywgMTUsIE5hTiwgMTksIDE3LCAxNCwgTmFOKQ0KDQpkIDwtIGlmZWxzZShpcy5uYShkYXRhKSB8IGlzLm5hbihkYXRhKSwgIm1pc3NpbmciLCBpZmVsc2UoZGF0YSA8IDEwLCAibG93IiwgaWZlbHNlKGRhdGEgPCAxNSwgIm1lZGl1bSIsICJoaWdoIikpKQ0KDQp0YWJsZShkKQ0KYGBgDQoNCiMjIEZ1bmN0aW9ucw0KQSBmdW5jdGlvbiBpcyBqdXN0IGFuIFIgb2JqZWN0IHRoYXQgcnVucyBhIHBlci1kZWZpbmVkIHNuaXBwZXQgb2YgY29kZSwgdXN1YWxseSBvbiBzb21lIGlucHV0IHRoYXQgeW91IHN1cHBseSB0byBpdC4gQSBmdW5jdGlvbiBjYW4gcmV0dXJuIGFuIG91dHB1dCBiYXNlZCBvbiB0aGUgaW5wdXQgeW91IHByb3ZpZGUuIEZvciBleGFtcGxlLCB0aGUgc3VtKCkgZnVuY3Rpb24gYnVpbHQgaW50byBSIHNpbXBseSB0YWtlcyBhIG51bWVyaWMgdmVjdG9yIGFzIGlucHV0IGFuZCByZXR1cm5zIHRoZWlyIHN1bSBhcyBvdXRwdXQuIEJ1aWx0LWluIGZ1bmN0aW9ucyBhbmQgcGFja2FnZXMgY2FuIHRha2UgeW91IGEgbG9uZyB3YXkgaW4gUiwgYnV0IGl0IGNhbiBiZSB1c2VmdWwgdG8gZGVmaW5lIHlvdXIgb3duIGZ1bmN0aW9ucyB0byBwZXJmb3JtIHNwZWNpZmljIHRhc2tzIG91dHNpZGUgdGhlIHNjb3BlIG9mIGJ1aWx0LWluIGZ1bmN0aW9ucy4NCg0KQ3JlYXRlIHlvdXIgb3duIGZ1bmN0aW9uIGluIFIgdXNpbmcgdGhpcyBzeW50YXg6DQoNCmBgYHtyfQ0KIyBBc3NpZ24gdGhlIGZ1bmN0aW9uKCkgdG8gYSBuYW1lIGFuZCBkZWNsYXJlIGFyZ3VtZW50cyB3aXRoaW4gKCkNCm5ld19mdW5jdGlvbiA8LSBmdW5jdGlvbihhcmd1bWVudHMpIHsNCiAgIyBXcml0ZSBhIGZ1bmN0aW9uIGJvZHkgd2l0aGluIHRoZSB7fSB0byBleGVjdXRlDQogIGZvciAoeCBpbiAxOmFyZ3VtZW50cykgew0KICAgIHByaW50KCJUaGlzIGlzIGEgZnVuY3Rpb24hIikNCiAgfQ0KfQ0KYGBgDQoNCkhlcmUgaXMgYW4gYWN0dWFsIGV4YW1wbGUNCg0KYGBge3J9DQpleGFtcGxlRnVuY3Rpb24gPC0gZnVuY3Rpb24oeCwgeSkgew0KICBjKHggKyAxLCB5ICsgMTApDQp9DQoNCmV4YW1wbGVGdW5jdGlvbigyLCA0KQ0KYGBgDQoNCioqRnVuY3Rpb25zIHdpdGggUmV0dXJuIFZhbHVlKioNCg0KRnVuY3Rpb25zIGluIFIgcmV0dXJuIHRoZSBsYXN0IGV4cHJlc3Npb24gZXZhbHVhdGVkIGJ5IGRlZmF1bHQuDQoNCmBgYHtyfQ0KYWRkXzEwIDwtIGZ1bmN0aW9uKG51bWJlcikgew0KICBudW1iZXIgKyAxMA0KICAjIHJldHVybiAobnVtYmVyKzEwKQ0KfQ0KDQphZGRfMTAoNSkNCg0KYWRkXzIwIDwtIGZ1bmN0aW9uKG51bWJlcikgew0KICByZXR1cm4obnVtYmVyICsgMjApICMgRXhpdCBhbmQgcmV0dXJuIHNwZWNpZmllZCB2YWx1ZQ0KICBudW1iZXIgKyAxMCAjIFRoZSBmdW5jdGlvbiBleGl0cyBiZWZvcmUgcnVubmluZyB0aGlzIGxpbmUNCn0NCmBgYA0KDQoNCiMjIEZ1bmN0aW9uIEFyZ3VtZW50cw0KDQpBIGZ1bmN0aW9uIGNhbiBoYXZlIG9uZSBvciBtb3JlIG5hbWVkIGFyZ3VtZW50cy4gWW91IGNhbiBhc3NpZ24gYSBkZWZhdWx0IHZhbHVlIHRvIGFuIGFyZ3VtZW50IHdoZW4gY3JlYXRpbmcgYSBmdW5jdGlvbiB3aXRoIHRoZSBhcmd1bWVudF9uYW1lID0gYXJndW1lbnRfdmFsdWUgc3ludGF4Lg0KDQpgYGB7cn0NCnN1bV8zX2l0ZW1zIDwtIGZ1bmN0aW9uKHgsIHksIHosIHByaW50X2FyZ3MgPSBUUlVFKSB7DQogIGlmIChwcmludF9hcmdzKSB7DQogICAgcHJpbnQoeCkNCiAgICBwcmludCh5KQ0KICAgIHByaW50KHopDQogIH0NCiAgcmV0dXJuKHggKyB5ICsgeikNCn0NCnN1bSA8LSBzdW1fM19pdGVtcygxLCAyLCAzKQ0Kc3VtMiA8LSBzdW1fM19pdGVtcygxMCwgMjAsIDMwLCBwcmludF9hcmdzID0gRkFMU0UpDQpgYGANCg0KKipFbGxpcHNpcyoqDQoNClRoZSAuLi4gYXJndW1lbnQgY29sbGVjdHMgYWxsIGV4dHJhIGFyZ3VtZW50cyBwYXNzZWQgdG8gYSBmdW5jdGlvbiB0aGF0IGFyZSBub3QgbWF0Y2hlZC4gVGhlIC4uLiBhcmd1bWVudCBjYW4gYmUgdXNlZCBpbiBmdW5jdGlvbnMgd2hlcmUgdGhlIG51bWJlciBvZiBhcmd1bWVudHMgaXMgbm90IGtub3duIGluIGFkdmFuY2UuDQoNCg0KYGBge3J9DQphZGRpdGlvbl9mdW5jdGlvbiA8LSBmdW5jdGlvbiguLi4pIHsNCiAgdG90YWwgPC0gMA0KICAjIGxpc3QgKC4uLikgZXh0cmFjdHMgdGhlIGFyZ3VtZW50cyB0byBhIGxpc3QNCiAgZm9yICh2YWx1ZSBpbiBsaXN0KC4uLikpIHsNCiAgICAjIEFkZCBlYWNoIGFyZ3VtZW50IGluIC4uLiB0byB0aGUgdG90YWwNCiAgICB0b3RhbCA8LSB0b3RhbCArIHZhbHVlDQogIH0NCiAgdG90YWwNCn0NCg0KYWRkaXRpb25fZnVuY3Rpb24oMiwgNCwgNiwgOCwgMTAsIDEyLCAxNCkNCmBgYA==